Hello I am developing a game on my spare time with AIDE and libGDX. Though AIDE has some missing methods of the libGDX API and I had to create some workarounds to compensate for the missing methods.
So my problem is that with every instance of a collision the app becomes more and more laggy. No new textures are being drawn and non go away. Just a poor implementation that is meant to push you out of said collision tile. It runs fine until you have a few collisions. My thought is that it creates a new variable with every collision and stores it into memory causing a leak. But I can't really tell if that is the case. Oh I'd like to add that I don't have access to a computer, just my phone. Here is my movement class
move.java
public class move
{
float posX;
float posY;
float touchedOnScreenX;
float touchedOnScreenY;
float centerOfScreenX;
float centerOfScreenY;
float posXSetter;
float posYSetter;
float Speed = 150;
float mapBoundsWidth;
float mapBoundsHeight;
boolean upperBounds;
boolean lowerBounds;
boolean rightBounds;
boolean leftBounds;
boolean tileCollition;
public move() {
}
public void renderMove(float delta) {
if(Gdx.input.isTouched()) {
screenAndTouchInfo();
checkBoundsBoolean();
checkForCollision();
}
}
//slows game down
private void checkForCollision()
{
if (upperBounds == false)
{
if (lowerBounds == false)
{
if (rightBounds == false)
{
if (leftBounds == false)
{
if (tileCollition == false)
{
movement();
}
else
{
collitionSide();
}
}
else
{
posX++;
}
}
else
{
posX--;
}
}
else
{
posY++;
}
}
else
{
posY --;
}
}
private void movement()
{
posYSetter = posY;
posXSetter = posX;
if (touchedOnScreenX < centerOfScreenX)
{
posX -= Gdx.graphics.getDeltaTime() * Speed;
}
else
{
posX += Gdx.graphics.getDeltaTime() * Speed;
}
if (touchedOnScreenY < centerOfScreenY)
{
posY -= Gdx.graphics.getDeltaTime() * Speed;
}
else
{
posY += Gdx.graphics.getDeltaTime() * Speed;
}
if (touchedOnScreenY < centerOfScreenY + 64 && touchedOnScreenY > centerOfScreenY - 64)
{
posY = posYSetter;
}
if (touchedOnScreenX < centerOfScreenX + 64 && touchedOnScreenX > centerOfScreenX - 64)
{
posX = posXSetter;
}
}
//buggy and slows game down. Can push you into tile if input is the opposite of the side
public void collitionSide() {
if (tileCollition == true){
if (touchedOnScreenX < centerOfScreenX)
{
posX = posX +10;
}
else
{
posX = posX - 10;
}
if (touchedOnScreenY < centerOfScreenY)
{
posY = posY +10;
}
else
{
posY = posY -10;
}
}
}
private void screenAndTouchInfo()
{
touchedOnScreenX = Gdx.input.getX();
touchedOnScreenY = (Gdx.graphics.getHeight() - Gdx.input.getY());
centerOfScreenX = Gdx.graphics.getWidth() / 2;
centerOfScreenY = Gdx.graphics.getHeight() / 2;
}
//slows game down
private void checkBoundsBoolean()
{
if (posX > mapBoundsWidth)
{
rightBounds = true;
}
else {
rightBounds = false;
}
if (posY > mapBoundsHeight)
{
upperBounds = true;
}
else {
upperBounds = false;
}
if (posX < mapBoundsWidth - mapBoundsWidth)
{
leftBounds = true;
}
else {
leftBounds = false;
}
if (posY < mapBoundsHeight - mapBoundsHeight)
{
lowerBounds = true;
}
else {
lowerBounds = false;
}
}
public void setTileCollision(boolean tileCollision) {
this.tileCollition = tileCollision;
}
public float getPosX() {
return posX;
}
public float getPosY() {
return posY;
}
public float getTouchedOnScreenX() {
return touchedOnScreenX;
}
public float getTouchedOnScreenY() {
return touchedOnScreenY;
}
public float getCenterOfScreenX() {
return centerOfScreenX;
}
public float getCenterOfScreenY() {
return centerOfScreenY;
}
public void setMapboundsWidth(float width) {
this.mapBoundsWidth = width;
}
public void setMapboundsHeight(float height) {
this.mapBoundsHeight = height;
}
}
I know that is a lot of code to comb through and I am sorry if it isn't always clear what is going on. I refactored it to where it would be a little easier to understand. Oh if anyone could tell me why AIDE is missing some methods of libGDX that would be nice too.The most notable one would be Cell.setTile(). That I know is in libGDX's API and can be found in their documentation. But when I implement it it throws a unknown method of class Cell error. I have researched on how to use the method as well with no avail. Had to create int[][] map and a for loop to draw map with another Texture[]. It works. Lol. Thank you to whomever even took the time to look at my long winded double question. Hopefully someone can tell me why this lag is created from said collisions.
I recommend moving your collision code into a separate thread. This should improve performance significantly:
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
// Physics loop goes here
}
});
Make sure to shutdown the executor when disposing your screen.
Related
my code have no error but ranking position is not working properly
how I change in my project. I want to make RPS in game.
public int currentCheckPoint, lapCount;
public float distance;
private Vector3 checkPoint;
public float counter;
public int rank;
public GameObject panelcar;
public GameObject losepanel;
void Start()
{
currentCheckPoint = 1;
StartCoroutine(LevelFail());
}
// Update is called once per frame
void Update()
{
CalculateDistance();
}
void CalculateDistance()
{
distance = Vector3.Distance(transform.position, checkPoint);
counter = lapCount * 1000 + currentCheckPoint * 100 + distance;
}
private void OnTriggerEnter(Collider other)
{
if(other.tag == "CheckPoint")
{
currentCheckPoint = other.GetComponent<CurrentCheckPoint>().currentCheckPointNumber;
checkPoint = GameObject.Find("CheckPoint" + currentCheckPoint).transform.position;
}
if(other.tag == "Finish")
{
if(gameObject.name == "Player")
{
panelcar.SetActive(true);
Time.timeScale = 0f;
AudioListener.volume = 0f;
}
if (gameObject.name == "Red Car" || gameObject.name == "Orrange Car" || gameObject.name == "yellow Car" || gameObject.name == "Blue Car" || gameObject.name == "Tursh Car")
{
losepanel.SetActive(true);
Time.timeScale = 0f;
AudioListener.volume = 0f;
}
}
}
I have a raycast going upwards from an object which when the player comes in contact with the ray the object changes color. That works but I want to do it so when you touch the ray a second time, the object gets destroyed and I have no idea how to do that. I'm using Unity 2d.
Code: `using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyEnemy : MonoBehaviour //Enemy 3
{
[SerializeField] Transform Enemy3WayPoint;
private Renderer rend;
private Color colorToTurnTo = Color.blue;
void Start()
{
rend = GetComponent<Renderer>();
rend.enabled = true;
Physics2D.queriesStartInColliders = false;
}
private void Update()
{
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector3.up, 5);
if (hitInfo.collider.gameObject.tag == "Player")
{
rend.material.color = colorToTurnTo;
Debug.DrawLine(transform.position, hitInfo.point, Color.white);
}`
There may be a bracket or two I forgot to include, it does work when I test it
I think the simplest solution is to use a variable to keep track of the number of times the ray has been hit by the player.
As for destroying the enemy, you can use the destroy function.
So, something like this:
int hitCount = 0; //add a class variable
void Update(){
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector3.up, 5);
if (hitInfo.collider.gameObject.tag == "Player")
{
hitCount++;
}
if(hitCount == 1)
{
rend.material.color = colorToTurnTo;
Debug.DrawLine(transform.position, hitInfo.point, Color.white);
}
else if(hitCount >= 2)
{
Destroy(gameObject); //this will destroy the gameObject that the component is attached to
}
}
EDIT: It seems the OP's main problem was adding a delay to the events. Here is some updated code that addresses that problem:
bool waitingForFirstHit = true;
bool waitingForSecondHit = false;
float timeDelay = 1.5f;
void Update(){
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector3.up, 5);
if (hitInfo.collider.gameObject.tag == "Player" )
{
if (waitingForFirstHit) {
ChangeColor();
waitingForFirstHit = false;
waitingForSecondHit = true;
}
else if(waitingForSecondHit && timeDelay < 0)
{
DestroyEnemy ();
}
}
if(waitingForSecondHit)
{
timeDelay -= Time.deltaTime;
}
}
void ChangeColor()
{
rend.material.color = colorToTurnTo;
Debug.DrawLine(transform.position, hitInfo.point, Color.white);
}
void DestroyEnemy()
{
Destroy(gameObject);
}
Here is a tutorial on using the Destroy function:
https://unity3d.com/learn/tutorials/topics/scripting/destroy
And here is a link to the docs:
https://docs.unity3d.com/ScriptReference/Object.Destroy.html
Cheers.
I am trying to make a sound play with the timer goes to 3, 2, 1.
My timer starts at ten and has a three second delay. If I use the following code:
if (tl.myCoolTimer == 10)
{
print("Play Sound");
myAudioSource.Play();
}
It plays the Beep over and over again until the game starts and the counter goes below 10.
If I use the code:
if (tl.myCoolTimer == 3)
{
print("Play Sound");
myAudioSource.Play();
}
It doesn't play the sound at all. It doesn't even print the print statement.
I literally only changed the number. I am not sure why this isn't working.
I have also tried setting it to 3f to see if it is a float issue.
Timer Scripts
This is the starting Timer. it counts down to 3 (then the game starts)
public Text startGameTimerText;
public float startGameTimer = 3;
public void Start ()
{
startGameTimerText = GetComponent<Text> ();
}
public void Update ()
{
startGameTimer -= Time.deltaTime;
startGameTimerText.text = startGameTimer.ToString ("f1");
if (startGameTimer < 0) {
GameObject.Find ("GameStartTimer").SetActive (false);
}
}
This is the Game Timer It starts at 10 and counts down to 0.
public StartGameTimer gt; //this is the script the other timer is on
public Text timerText;
public float myCoolTimer = 10;
public void Start ()
{
timerText = GetComponent<Text> ();
}
public void Update ()
{
if (gt.startGameTimer > 0) {
myCoolTimer = 10;
} else {
myCoolTimer -= Time.deltaTime;
timerText.text = myCoolTimer.ToString ("f1");
}
}
Thanks Joe for the help. Here was my final answer. I know it is hacked, but I haven't figured out the Invoke thing yet. When I set the into it kept playing the entire time it was at "3", so i need to make it play only once.
private AudioSource myAudioSource;
public bool isSoundPlayed;
void Start()
{
myAudioSource = GetComponent<AudioSource>();
isSoundPlayed = false;
}
void Update()
{
if((int)tl.myCoolTimer == 3)
{
if (isSoundPlayed == false)
{
myAudioSource.Play();
isSoundPlayed = true;
}
return;
}
if ((int)tl.myCoolTimer == 2)
{
if (isSoundPlayed == true)
{
myAudioSource.Play();
isSoundPlayed = false;
}
return;
}
if ((int)tl.myCoolTimer == 1)
{
if (isSoundPlayed == false)
{
myAudioSource.Play();
isSoundPlayed = true;
}
return;
}
}
I was working on massive collision detection for my game(more than 1000 sprites is massive for my game), and i was searching to find a way to implement this, then i reached to quad tree:
http://en.wikipedia.org/wiki/Quadtree
Well it's approach to reduce the number of objects that should be check for collision by dividing them to the groups of objects which have more chance to collide.
I found a java version of quad tree here:
http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/
Then i change it and use it for my javafx game. but the performance wasn't really good for huge number of objects, so i made some optimisation on it.
Well i used AnimationTimer for each tree to check for collisions which has improved performance so much. i think Animation Timer use GPU to process because when i run my code CPU usage doesn't go hight(3% to 5% - 1640 sprites). but if i use Thread instead of AnimationTimer it use much more CPU(about 40% to 50% - 1640 sprites).
import java.util.ArrayList;
import java.util.List;
import javafx.animation.AnimationTimer;
import javafx.scene.layout.Region;
import javafx.scene.layout.RegionBuilder;
import javafx.scene.paint.Color;
import viwofx.sprit.Sprite;
import viwofx.ui.GameScene;
public class QuadTree
{
private int MAX_OBJECTS = 10;
private int MAX_LEVELS = 5;
private int level;
private ArrayList<Sprite> sprites;
private ArrayList<Sprite> unAllocatedSprites;
private Region bounds;
private QuadTree[] nodes;
private QuadTree parent;
private AnimationTimer detection;
private boolean detecting = false;
private QuadTree getqt()
{
return this;
}
public QuadTree(QuadTree p, int pLevel, Region pBounds)
{
this.parent = p;
level = pLevel;
sprites = new ArrayList<>(0);
unAllocatedSprites = new ArrayList<>(0);
bounds = pBounds;
nodes = new QuadTree[4];
detection = new AnimationTimer()
{
#Override
public void handle(long l)
{
// This for happens when this node has child nodes and there is some object which can not fit whitin the bounds of child nodes
// these object being checked till they can fit inside the bounds of child nodes then they will be added to correspinding child node,
// or object is out of bounds then it will be pushed to the parent node
for (int i = 0; i < unAllocatedSprites.size(); i++)
{
if (!isInside(unAllocatedSprites.get(i)))
{
pushToParent(unAllocatedSprites.get(i));
continue;
}
int index = getIndex(unAllocatedSprites.get(i));
if (index != -1)
{
nodes[index].add(unAllocatedSprites.remove(i));
}
}
for (int i = 0; i < sprites.size(); i++)
{
Sprite ts = sprites.get(i);
if (isInside(ts))
{
int ii = 0;
for (ii = 0; ii < sprites.size(); ii++)
{
Sprite ts2 = sprites.get(ii);
if (ts != ts2)
{
Your collision detection logic
}
}
if (parent != null)
{
for (ii = 0; ii < parent.getUnAllocatedSprites().size(); ii++)
{
Sprite ts2 = parent.getUnAllocatedSprites().get(ii);
if (ts != ts2 && isInside(ts2))
{
Your collision detection logic
}
}
}
}
else
{
pushToParent(ts);
}
}
}
};
}
public int getLevel()
{
return level;
}
public ArrayList<Sprite> getUnAllocatedSprites()
{
return unAllocatedSprites;
}
// Split the node into 4 subnodes
private void split()
{
double subWidth = (bounds.getPrefWidth() / 2);
double subHeight = (bounds.getPrefHeight() / 2);
double x = bounds.getLayoutX();
double y = bounds.getLayoutY();
nodes[0] = new QuadTree(this, level + 1, RegionBuilder.create().layoutX(x).layoutY(y).prefWidth(subWidth).prefHeight(subHeight).build());
nodes[1] = new QuadTree(this, level + 1, RegionBuilder.create().layoutX(x + subWidth).layoutY(y).prefWidth(subWidth).prefHeight(subHeight).build());
nodes[2] = new QuadTree(this, level + 1, RegionBuilder.create().layoutX(x).layoutY(y + subHeight).prefWidth(subWidth).prefHeight(subHeight).build());
nodes[3] = new QuadTree(this, level + 1, RegionBuilder.create().layoutX(x + subWidth).layoutY(y + subHeight).prefWidth(subWidth).prefHeight(subHeight).build());
}
private int getIndex(Sprite s)
{
int index = -1;
double verticalMidpoint = bounds.getLayoutX() + (bounds.getPrefWidth() / 2);
double horizontalMidpoint = bounds.getLayoutY() + (bounds.getPrefHeight() / 2);
double spriteMaxX = (s.getNode().getTranslateX() + s.getWidth());
double spriteMaxY = (s.getNode().getTranslateY() + s.getHeight());
// Object can completely fit within the top quadrants
boolean topQuadrant = (spriteMaxY < horizontalMidpoint);
// Object can completely fit within the bottom quadrants
boolean bottomQuadrant = (s.getNode().getTranslateY() >= horizontalMidpoint);
// Object can completely fit within the left quadrants
if (s.getNode().getTranslateX() >= bounds.getLayoutX() && spriteMaxX < verticalMidpoint)
{
if (topQuadrant)
{
index = 0;
}
else if (bottomQuadrant)
{
index = 2;
}
}
// Object can completely fit within the right quadrants
else if (s.getNode().getTranslateX() >= verticalMidpoint && (s.getNode().getTranslateX() + s.getWidth()) < (bounds.getLayoutX() + bounds.getPrefWidth()))
{
if (topQuadrant)
{
index = 1;
}
else if (bottomQuadrant)
{
index = 3;
}
}
return index;
}
public boolean isInside(Sprite s)
{
double maxX = bounds.getLayoutX() + bounds.getPrefWidth();
double maxY = bounds.getLayoutY() + bounds.getPrefHeight();
// Object can completely fit within the left quadrants
if (s.getNode().getTranslateX() >= bounds.getLayoutX() && (s.getNode().getTranslateX() + s.getWidth()) < maxX && s.getNode().getTranslateY() >= bounds.getLayoutY() && (s.getNode().getTranslateY() + s.getHeight()) < maxY)
{
return true;
}
if (parent != null && parent.getUnAllocatedSprites().contains(s))
{
return true;
}
return false;
}
public void pushToParent(Sprite s)
{
sprites.remove(s);
unAllocatedSprites.remove(s);
if (parent == null)
{
//System.out.println("parent");
if (!unAllocatedSprites.contains(s))
{
unAllocatedSprites.add(s);
}
return;
}
parent.add(s);
if (sprites.size() < 1 && unAllocatedSprites.size() < 1)
{
stopDetection();
}
}
public void add(viwofx.sprit.Sprite sprite)
{
// if sprite is not fit in the bounds of node, it will be pushed to the parent node.
// this is a optimization for when child node push a object to this node and object still is not fit in the bounds this node,
// so it will be pushed to the parent node till object can be fited whitin the node bounds
// this if prevent of out of bounds object to being added to unAllocatedSprites and then being pushed to parent
if (!isInside(sprite))
{
pushToParent(sprite);
return;
}
// if tree has been splited already add sprite to corrosponding child
if (nodes[0] != null)
{
int index = getIndex(sprite);
if (index != -1)
{
nodes[index].add(sprite);
return;
}
else
{
unAllocatedSprites.add(sprite);
return;
}
}
sprites.add(sprite);
if (!detecting)
{
startDetection();
}
if (sprites.size() > MAX_OBJECTS && level < MAX_LEVELS)
{
if (nodes[0] == null)
{
split();
}
int i = 0;
while (i < sprites.size())
{
int index = getIndex(sprites.get(i));
if (index != -1)
{
nodes[index].add(sprites.remove(i));
}
else
{
unAllocatedSprites.add(sprites.remove(i));
}
}
}
}
public List<Sprite> retrieve(List<Sprite> returnObjects, Sprite pRect)
{
int index = getIndex(pRect);
if (index != -1 && nodes[0] != null)
{
nodes[index].retrieve(returnObjects, pRect);
}
returnObjects.addAll(sprites);
return returnObjects;
}
public void startDetection()
{
detecting = true;
detection.start();
}
public void stopDetection()
{
//detecting = false;
//detection.stop();
}
}
I hope this will be helpful for you.
I'm missing something fundamental, and probably both simple and obvious.
My issue:
I have a view (CPlaybackView, derived from CView).
The view displays a bunch of objects derived from CRectTracker (CMpRectTracker).
These objects each contain a floating point member.
I want to display that floating point member when the mouse hovers over the CMpRectTracker.
The handler method is never executed, although I can trace through OnIntitialUpdate, PreTranslateMessage,
and OnMouseMove.
This is in Visual C++ v. 6.0.
Here's what I've done to try to accomplish this:
1. In the view's header file:
public:
BOOL OnToolTipNeedText(UINT id, NMHDR * pNMHDR, LRESULT * pResult);
private:
CToolTipCtrl m_ToolTip;
CMpRectTracker *m_pCurrentRectTracker;//Derived from CRectTracker
2. In the view's implementation file:
a. In Message Map:
ON_NOTIFY_EX(TTN_NEEDTEXT,0,OnToolTipNeedText)
b. In CPlaybackView::OnInitialUpdate:
if (m_ToolTip.Create(this, TTS_ALWAYSTIP) && m_ToolTip.AddTool(this))
{
m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_AUTOPOP, SHRT_MAX);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_INITIAL, 200);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_RESHOW, 200);
}
else
{
TRACE("Error in creating ToolTip");
}
this->EnableToolTips();
c. In CPlaybackView::OnMouseMove:
if (::IsWindow(m_ToolTip.m_hWnd))
{
m_pCurrentRectTracker = NULL;
m_ToolTip.Activate(FALSE);
if(m_rtMilepostRect.HitTest(point) >= 0)
{
POSITION pos = pDoc->m_rtMilepostList.GetHeadPosition();
while(pos)
{
CMpRectTracker tracker = pDoc->m_rtMilepostList.GetNext(pos);
if(tracker.HitTest(point) >= 0)
{
m_pCurrentRectTracker = &tracker;
m_ToolTip.Activate(TRUE);
break;
}
}
}
}
d. In CPlaybackView::PreTranslateMessage:
if (::IsWindow(m_ToolTip.m_hWnd) && pMsg->hwnd == m_hWnd)
{
switch(pMsg->message)
{
case WM_LBUTTONDOWN:
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
m_ToolTip.RelayEvent(pMsg);
break;
}
}
e. Finally, the handler method:
BOOL CPlaybackView::OnToolTipNeedText(UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{
BOOL bHandledNotify = FALSE;
CPoint CursorPos;
VERIFY(::GetCursorPos(&CursorPos));
ScreenToClient(&CursorPos);
CRect ClientRect;
GetClientRect(ClientRect);
// Make certain that the cursor is in the client rect, because the
// mainframe also wants these messages to provide tooltips for the
// toolbar.
if (ClientRect.PtInRect(CursorPos))
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
CString str;
str.Format("%f", m_pCurrentRectTracker->GetMilepost());
ASSERT(str.GetLength() < sizeof(pTTT->szText));
::strcpy(pTTT->szText, str);
bHandledNotify = TRUE;
}
return bHandledNotify;
}
Got it:
Just to put it to bed, here's the result:
BEGIN_MESSAGE_MAP(CPlaybackView, CThreadView)
ON_NOTIFY_EX(TTN_NEEDTEXT,0,OnToolTipNeedText)
END_MESSAGE_MAP()
void CPlaybackView::OnInitialUpdate()
{
if (m_ToolTip.Create(this, TTS_ALWAYSTIP) && m_ToolTip.AddTool(this))
{
m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_AUTOPOP, 2000);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_INITIAL, 1);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_RESHOW, 1);
m_ToolTip.Activate(FALSE);
BOOL ena = EnableToolTips(TRUE);
}
else
{
TRACE("Error in creating ToolTip");
}
}
void CPlaybackView::OnMouseMove(UINT nFlags, CPoint point)
{
CPlaybackDoc* pDoc = (CPlaybackDoc*) GetDocument();
if (::IsWindow(m_ToolTip.m_hWnd))
{
CMpRectTracker *pRectTracker = HitTest(point);
if(pRectTracker)
{
m_ToolTip.Activate(TRUE);
}
else
{
m_ToolTip.Activate(FALSE);
}
}
}
BOOL CPlaybackView::OnToolTipNeedText(UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{
BOOL bHandledNotify = FALSE;
CPoint CursorPos;
VERIFY(::GetCursorPos(&CursorPos));
ScreenToClient(&CursorPos);
CRect MilepostRect;
m_rtMilepostRect.GetTrueRect(MilepostRect);
// Make certain that the cursor is in the client rect, because the
// mainframe also wants these messages to provide tooltips for the
// toolbar.
if(MilepostRect.PtInRect(CursorPos))
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
CMpRectTracker *pRectTracker = HitTest(CursorPos);
if(pRectTracker)
{
CString str;
str.Format("%f", pRectTracker->GetMilepost());
ASSERT(str.GetLength() < sizeof(pTTT->szText));
::strcpy(pTTT->szText, str);
bHandledNotify = TRUE;
}
}
return bHandledNotify;
}
BOOL CPlaybackView::PreTranslateMessage(MSG* pMsg)
{
if (::IsWindow(m_ToolTip.m_hWnd) && pMsg->hwnd == m_hWnd)
{
switch(pMsg->message)
{
case WM_LBUTTONDOWN:
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
m_ToolTip.RelayEvent(pMsg);
break;
}
}
return CView::PreTranslateMessage(pMsg);
}
CMpRectTracker* CPlaybackView::HitTest(CPoint &point)
{
CPlaybackDoc* pDoc = (CPlaybackDoc*) GetDocument();
ASSERT_VALID(pDoc);
CMpRectTracker *pTracker = NULL;
POSITION pos = pDoc->m_rtMilepostList.GetHeadPosition();
while(pos)
{
CMpRectTracker tracker = pDoc->m_rtMilepostList.GetNext(pos);
if(tracker.HitTest(point) >= 0)
{
m_CurrentRectTracker = tracker;
pTracker = &m_CurrentRectTracker;
break;
}
}
return pTracker;
}