首先说一下上次作业助教老师那里依然没有得到代码的问题,我在截止日期之前已经提交过一次,主要算法都写完了,如博客所写,但是中间不知道哪里出问题了,上交github的那份编译死活通不过,所以最后只有悲剧的博客分。
坦白的说最近两次作业已经开始超越学生的能力范围,不得不承认自己进入大学无所事事很久,邹老师的课跳跃性很大,讲的夜很深,对基础能力要求也很高,一直没有实用过动态规划什么的也开始使用。关于结对编程,那些大牛们都跑到牛群里了,平时早都结好了,我等弱小的牛只能互相衔持,偶尔难得某只大牛心情好来给我们指点一二。下面是这次作业,尽管UI神马的完全没弄明白。
一,设计思路
目标明确,编写Ui界面,在第二次作业无论是连通图还是非连通图都是控制台输入输出,没有考虑具体的位置,所以修改的模块应该是位于比较大小选择的地方,每次比较将位置明确,进而在UI中修改。
此外保证只有一个界面在系统中运行,并且还要进行更新,这个确实很难做到。查看了设计模式中的单例模式,经过研究后发现单例模式适用情景是一个程序中只有一个类实例,而第3次作业其实并不是一个单例模式,只能说是“单界面”。单界面本身并不难做到,只要在程序运行的开头判断一下是否已经有界面即可。但是难点就在于,如果在已经有界面的情况下再次运行命令,不仅要保证单界面,还要使新命令的结果也添加到界面上。这个最主要的问题就是如何使新命令传递给已经存在的界面。
最后还有一个移动矩形问题。。。和第二问一样远远凌驾于本人能力之上。。。。
虽然没有能够完成本次作业,但是无论课程上的学习还是课后自己学习都没有放松,正在自修python,希望期末之前能跟上进度,完成之前落下的作业。以下是Python编写的小程序,3D界面:
代码:
import direct.directbase.DirectStart,random, sys, os, math from direct.showbase.ShowBase import ShowBase from panda3d.core import AmbientLight,DirectionalLight from panda3d.core import TextNode,NodePath,LightAttrib from panda3d.core import CollisionTraverser,CollisionNode from panda3d.core import CollisionHandlerQueue,CollisionRay from panda3d.core import Filename,AmbientLight,DirectionalLight from panda3d.core import PandaNode,NodePath,Camera,TextNode from panda3d.core import Vec3,Vec4,BitMask32 from direct.gui.OnscreenText import OnscreenText from direct.actor.Actor import Actor from direct.showbase.DirectObject import DirectObject from math import pi, sin, cos from direct.task import Task from direct.interval.IntervalGlobal import Sequence from panda3d.core import Point3 SPEED = 0.5 # Function to put instructions on the screen. def addInstructions(pos, msg): return OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-1.3, pos), align=TextNode.ALeft, scale = .05) def addTitle(text): return OnscreenText(text=text, style=1, fg=(1,1,1,1), pos=(1.3,-0.95), align=TextNode.ARight, scale = .07) class World(DirectObject): def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0,"down":0} base.win.setClearColor(Vec4(0,0,0,1)) # Post the instructions self.title = addTitle("Roaming MyPanda for 11061107~") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right") self.inst8 = addInstructions(0.60, "[1]: teacup") self.inst9 = addInstructions(0.55, "[2]: candy") self.inst10 = addInstructions(0.50, "[3]: xiangjiao") self.inst11 = addInstructions(0.45, "[4]: sword") # self.spotlight = camera.attachNewNode( Spotlight( "spotlight" ) ) # self.spotlight.node().setColor( Vec4( .45, .45, .45, 1 ) ) # #The cone of a spotlight is controlled by it's lens. This creates the lens # self.spotlight.node().setLens( PerspectiveLens() ) # #This sets the Field of View (fov) of the lens, in degrees for width and # #height. The lower the numbers, the tighter the spotlight. # self.spotlight.node().getLens().setFov( 16, 16 ) # # Attenuation controls how the light fades with distance. The numbers are # # The three values represent the three constants (constant, linear, and # # quadratic) in the internal lighting equation. The higher the numbers the # # shorter the light goes. # self.spotlight.node().setAttenuation( Vec3( 1, 0.0, 0.0 ) ) # # This exponent value sets how soft the edge of the spotlight is. 0 means a # # hard edge. 128 means a very soft edge. # # self.spotlight.node().setExponent( 60.0 ) # render.setLight( self.spotlight ) # self.accept( "x", self.toggleLights, [[self.spotlight]] ) # def toggleLights( self, lights ): # for light in lights: # #If the given light is in our lightAttrib, remove it. # #This has the effect of turning off the light # if render.hasLight(light): # render.clearLight(light) # #Otherwise, add it back. This has the effect of turning the light on # else: # render.setLight(light) # self.updateStatusLabel() # # # This function toggles the spinning of the point intervals by pausing and # # resuming the interval # def toggleSpinningPointLights( self ): # if self.arePointLightsSpinning: self.pointLightsSpin.pause() # else: self.pointLightsSpin.resume() # self.arePointLightsSpinning = not self.arePointLightsSpinning # self.updateStatusLabel() # # # This function turns per-pixel lighting on or off. # def togglePerPixelLighting( self ): # if self.perPixelEnabled: # self.perPixelEnabled = False # render.clearShader() # else: # self.perPixelEnabled = True # render.setShaderAuto() # self.updateStatusLabel() # # # This function turns shadows on or off. # def toggleShadows( self ): # if self.shadowsEnabled: # self.shadowsEnabled = False # self.directionalLight.node().setShadowCaster(False) # else: # if not self.perPixelEnabled: # self.togglePerPixelLighting() # self.shadowsEnabled = True # self.directionalLight.node().setShadowCaster(True, 512, 512) # self.updateStatusLabel() # # #This function changes the spotlight's exponent. It is kept to the range # #0 to 128. Going outside of this range causes an error # def adjustSpotlightExponent( self, spotlight, amount ): # e = restrain(spotlight.node().getExponent() + amount, 0, 128) # spotlight.node().setExponent( e ) # self.updateStatusLabel() # # #This function reads the color of the light, uses a built-in python function # #(from the library colorsys) to convert from RGB (red, green, blue) color # #representation to HSB (hue, saturation, brightness), so that we can get the # #brighteness of a light, change it, and then convert it back to rgb to chagne # #the light's color # def addBrightness( self, light, amount ): # color = light.node().getColor() # h, s, b = colorsys.rgb_to_hsv( color[0], color[1], color[2] ) # brightness = restrain(b + amount) # r, g, b = colorsys.hsv_to_rgb( h, s, brightness ) # light.node().setColor( Vec4( r, g, b, 1 ) ) # # self.updateStatusLabel() # # # #Returns the brightness of a light as a string to put it in the instruction # #labels # def getBrightnessString( self, light ): # color = light.node().getColor() # h, s, b = colorsys.rgb_to_hsv( color[0], color[1], color[2] ) # return "%.2f" % b # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left",1]) self.accept("arrow_right", self.setKey, ["right",1]) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("a", self.setKey, ["cam-left",1]) self.accept("s", self.setKey, ["cam-right",1]) self.accept("arrow_down", self.setKey, ["down",1]) self.accept("arrow_down-up", self.setKey, ["down",0]) self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("a-up", self.setKey, ["cam-left",0]) self.accept("s-up", self.setKey, ["cam-right",0]) taskMgr.add(self.move,"moveTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,1000) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays #self.ralphGroundColNp.show() #self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-5, -5, -5)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.ralph) if (self.keyMap["cam-left"]!=0): base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-right"]!=0): base.camera.setX(base.camera, +20 * globalClock.getDt()) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -25 * globalClock.getDt()) if (self.keyMap["down"]!=0): self.ralph.setY(self.ralph, +25 * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0 ) or (self.keyMap["down"]!=0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk",5) self.isMoving = False # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec*(5-camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.0) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) return task.cont w = World() run()
主体部分参照过教程,但是插入人物以及运动部分自行编写
效果如图:
聊以表示没有纯粹混过,还是认真学习的态度